#!/usr/bin/perl
# modified by Zhang Jun at 2006/10/31 06:22:55
# created by Wang Jun at 2002
#
use warnings;
use strict;
use Getopt::Long;
use Pod::Usage;
use LWP;
use Encode;
use HTML::TreeBuilder;
use Tk;
use Tk::Tree;
use Tk::Adjuster;
use Tk::Dialog;

my $help;
my $PROXY;
my $url;
GetOptions ("help" => \$help,"proxy=s"=>\$PROXY,"url=s"=>\$url);
pod2usage(-exitstatus => 0, -verbose => 2) if $help;

my $file_name; #open filename
my $tb;  #Instance of TreeBuiler
my $tv;  #Instance of TreeView
my $encoding_type='gbk';
#Main Window

my $top = MainWindow->new('-title' => "HTML DOM-Tree Viewer"
    );

#Layout
my $menu_bar = $top->Frame(-borderwidth => 2,
                           -relief =>'groove')->pack('-anchor' => 'w',
                                                     '-side' => 'top',
                                                     '-fill' => 'x'
    );
my $tf1 = $top->Frame('-height' => 800,'-width' => 200);
my $ad = $top->Adjuster();
my $tf2 = $top->Frame('-height' => 800,'-width' => 400);

my $side = 'left';
$tf1->pack(-side => $side, -fill => 'both', -expand => 1);
$ad->packAfter($tf1, -side => $side);
$tf2->pack(-side => $side, -fill => 'both', -expand => 1);

#File Menu Button
my $file_mb = $menu_bar->Menubutton('-text'         => 'File',
                                    '-relief'       => 'flat',
                                    '-borderwidth'  => 2,
    )->pack('-side' => 'left','-padx' => 2);

#Sub-Menu under File Menu
#Exit Menu
$file_mb->command('-label'       => 'Open url',
                  '-accelerator' => 'Ctrl+O',
#                  '-underline'   => 2,
                  '-command'     => sub{open_link($file_mb);}
    );

#Exit Menu
$file_mb->command('-label'       => 'Exit',
                  '-accelerator' => 'Ctrl+X',
                  '-underline'   => 2,
                  '-command'     => [$top => 'destroy']
    );

#File Menu Button
my $view_mb = $menu_bar->Menubutton('-text'         => 'View',
                                    '-relief'       => 'flat',
                                    '-borderwidth'  => 2,
    )->pack('-side' => 'left','-padx' => 2);
my $vs = 1;
$view_mb->checkbutton('-label'    => 'View source',
                      '-variable' => \$vs);



#Help Menu Button
my $help_mb = $menu_bar->Menubutton('-text'         => 'Help',
                                    '-relief'       => 'flat',
                                    '-borderwidth'  => 2,
    )->pack('-side' => 'right','-padx' => 2);

#Sub-Menu under Help Menu
#About Menu
$help_mb->command('-label'       => 'About',
                  '-accelerator' => 'Ctrl+A',
                  '-underline'   => 0,
                  '-command'     => sub {show_aboutbox($help_mb);}
    );


createtree($tf1,$tf2,\$tv,\$tb) if($url);
MainLoop();

if ($tb) {
    $tb = $tb->delete;
}


##############################################################
sub createtree {
    
    my ($tf1,$tf2,$r_tv,$r_tb) = @_;
    $top->title('HTML DOM-Tree Viewer '.$url);

    if ($url) {
        if ($$r_tb) {
            $$r_tb->delete;
        }
        $$r_tb = HTML::TreeBuilder->new;
        
        my $agent = LWP::UserAgent->new;
        $agent->proxy('http'=>$PROXY);
        $agent->agent("Mozilla/5.0");
        my $response = $agent->get($url);
        print "get ok\n";
        my $content = $response->decoded_content();
        die if not defined $content;
        #my $h=$content->headers;
        #$encoding_type=$h->content_encoding;
        $$r_tb->parse($content);
        $$r_tb->objectify_text();

        if ($$r_tv) {
            $$r_tv->packForget();
        }
        $$r_tv = $tf1->Scrolled('Tree',
                                '-indent' => 15,
                                '-scrollbars' => 'osoe',
            )->pack('-fill'   => 'both',
                    '-expand' => 1);

        $$r_tv->configure( -opencmd => sub { open_node( $$r_tv,$$r_tb,@_ ); } ,
                           -command => sub { command_act($$r_tv,@_);},
                           -browsecmd => sub {view_attr($tf2,$$r_tb,@_);}
            );


        $$r_tv->add($$r_tb->address(),'-itemtype' => 'imagetext','-text' => $$r_tb->tag);
        $$r_tv->setmode($$r_tb->address(),"open");
    }
}

sub command_act {
    my ($tv,$address) = @_;
    my $mode = $tv->getmode($address);
    if ($mode eq "close") {
        $tv->close($address);
    }
    elsif ($mode eq "open") {
        $tv->open($address);
    }
}

sub open_node {
    my ($tv,$tb,$address) = @_;

    if( my @kids = $tv->infoChildren( $address ) ) {
        foreach my $kid (@kids) {
            $tv->show( -entry => $kid );
        }
        return;
    }

    my $node = $tb->address($address);
    my @nodes = $node->content_list();
    return unless @nodes;
    foreach my $cur_node (@nodes) {
        if ($cur_node->is_empty()) {
            $tv->add($cur_node->address(),'-itemtype' => 'imagetext','-text' => $cur_node->tag);
        }
        else {
            $tv->add($cur_node->address(),'-itemtype' => 'imagetext','-text' => $cur_node->tag);
            $tv->setmode($cur_node->address(),"open");
        }
    }
}

sub view_attr {
    my ($tf2,$tb,$address) = @_;
    my $node = $tb->address($address);

    my @ws = $tf2->packSlaves;

    foreach my $w (@ws) {
        $w->packForget;
    }
    
    if ($node->tag eq '~text') {
        my $t = $tf2->Scrolled('Text',
                               '-scrollbars' => 'osoe',
                               '-wrap' => 'char'
            )->pack('-fill'   => 'both',
                    '-expand' => 1);
        my $txt = $node->attr('text');
        #$txt = decode($encoding_type,$txt);
        $t->insert('1.0',$txt);
        $t->configure('-state' => 'normal');
    } else {
        my @attrs = $node->all_external_attr_names();

        if (@attrs) {
            foreach my $attr (@attrs) {
                my $l = $tf2->Label('-text' => $attr.':   '.$node->attr($attr),
                                    '-anchor' => 'nw'
                    )->pack('-side' => 'top',
                            '-fill' => 'x'
                    );
            }
            
        }
        my $add_str = substr($address,0,3);
        
        if ($add_str ne '0.0') {
            my @tps = $node->look_down('_tag','~text', sub {
                my $p_tag = $_[0]->parent->tag;
                $p_tag ne 'script'&& $p_tag ne 'style' && $p_tag ne 'option';
                                       }
                );
            my $txt = '';
            foreach my $tp (@tps) {
                $txt .= $tp->attr('text');
            }

            my $anchor_text = '';
            for (@{  $node->extract_links('a', 'href')  }) {
                my($link, $element, $attr, $tag) = @$_;
                $element->deobjectify_text();
                $anchor_text .= $element->as_text;
                $element->objectify_text();
            }
            my $ratio = 0;
            if ($txt) {
                $ratio = length($anchor_text)/length($txt);
            }

            my $r_str = '';
            if ($ratio>0) {
                $r_str = "RATIO=$ratio";
            }

            my $view_btn = $tf2->Button('-text' => "ADDRESS=$address   ".$r_str,
                                        '-command' => sub {viewbybrowser($address);}
                )->pack('-side' => 'top',
                        '-fill' => 'x'
                    );
        }

        my $t2 = $tf2->Scrolled('Text',
                                '-scrollbars' => 'osoe',
                                '-wrap' => 'none',
            );
        
        $t2->pack(-side => 'top',
                  '-fill'   => 'both',
                  '-expand' => 1);
        if ($vs) {
            $node->deobjectify_text();
            my $html = $node->as_HTML('<>&',"\t");
            my $nbsp = "\xa0";
            $html =~ s/$nbsp/&nbsp;/g;
            $node->objectify_text();

            #$html = decode($encoding_type,$html);
            $t2->insert('1.0',$html);
        }
        #$t2->configure('-state' => 'disable');
    }
}

sub open_link{
    my ($menu) = @_;
    my $dialog = $menu->Dialog(-title => 'Input the URL plz',
                               -default_button => "OK",
                               -buttons => [qw/Cancel/]
        );

    my $text1=$dialog->Text('-width'=>50, '-height'=> 1
        ) -> pack(-side => 'top',-fill=>'both');
    $dialog->Button(-text => "OK", -width=>10, -command => sub{open_link_impl($text1);$dialog->destroy();}
        )-> pack(-side => 'bottom');
    $dialog->Show();
}

sub open_link_impl{
    $url = $_[0]->get("1.0","end");
    createtree($tf1,$tf2,\$tv,\$tb) if($url);
}


sub show_aboutbox {
    my ($menu) = @_;
    my $dialog = $menu->Dialog(-title => 'About',
                               -text => "HTML DOM-Tree Viewer Ver. 0.1",
                               -default_button => "OK",
                               -buttons => [qw/OK/]
        );
    $dialog->Show();
}

sub viewbybrowser {
    my ($address) = @_;
    my $node = $tb->address($address);
    $node->deobjectify_text();
    my $src = $node->as_HTML('<>&',"\t");
    my $nbsp = "\xa0";
    $src =~ s/$nbsp/&nbsp;/g;
    $node->objectify_text();

    open(FH,">c:/temp999.htm") ||die "Can't create the file!";

    print FH $src;

    close(FH);
    system("explorer file://c:/temp999.htm");
}

__END__

=head1 NAME

HTML DOM Viewer

=head1 SYNOPSIS

./test.pl [options] 

Options:

=head1 OPTIONS

=over 8

=item B<-help>

print this and exit

=item B<-proxy>

set the proxy used to access internet

=item B<-url>

the URL to parse default

=back

=head1 DESCRIPTION

B<This program> is a program to show the DOM tree of a web page.

=head1 AUTHOR

Jun Zhang <jzhang533@gmail.com>

=cut


